package 加密与安全;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

//使用PKCS8EncodedKeySpec生成私钥，使用X509EncodedKeySpec生成公钥。此外，使用Base64进行解码和编码.
public class RSA加解密 {
	private static final String KEY_ALGORITHM = "RSA";
	private static final String PUBLIC_KEY = "publicKey";
	private static final String PRIVATE_KEY = "privateKey";

	public static void main(String[] args) throws Exception {
		Map<String, String> keyMap = genKey();
		RSAPublicKey publicKey = getPublicKey(keyMap.get(PUBLIC_KEY));
		RSAPrivateKey privateKey = getPrivateKey(keyMap.get(PRIVATE_KEY));
		String info = "明文123456gfsdgsgfg发给";
		// 加密
		byte[] bytes = encrypt(info.getBytes(StandardCharsets.UTF_8), publicKey);
		// 解密
		bytes = decrypt(bytes, privateKey);
		String plainText = new String(bytes, StandardCharsets.UTF_8);
		System.out.println("解密:" + plainText);
		
	}

	/**
	 * 返回 Base64 编码后的加密字符串
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptToBase64(byte[] data, RSAPublicKey publicKey) throws Exception {
		return Base64.encodeBase64String(encrypt(data, publicKey));
	}

	/**
	 * 加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, RSAPublicKey publicKey) throws Exception {
		// 构建 RSA 的秘钥工厂
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 创建RSA的Cipher对象，并提供加密功能
		System.out.println("algorithm: "+keyFactory.getAlgorithm());//RSA
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		// Cipher对象需要初始化
		// ENCRYPT_MODE 加密模式
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 得到需要加密后的二进制数据
		return cipher.doFinal(data);
	}

	/**
	 * 解密
	 * 
	 * @param data
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	private static byte[] decrypt(byte[] data, RSAPrivateKey privateKey) throws Exception {
		// 构建 RSA 的秘钥工厂
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 数据解密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		// Cipher对象需要初始化
		// DECRYPT_MODE 解密模式
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(data);
	}

	/**
	 * 取的秘钥对
	 * 
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static Map<String, String> genKey() throws NoSuchAlgorithmException {
		Map<String, String> keyMap = new HashMap<String, String>();
		// 实例化秘钥生成器
		KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);//RSA
		SecureRandom random = new SecureRandom();
		// random.setSeed(keyInfo.getBytes());
		// 设置秘钥位数，512位已被破解，用1024位,最好用2048位
		keygen.initialize(1024, random);
		// 生成秘钥对
		KeyPair kp = keygen.generateKeyPair();
		// 私钥对象
		RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
		// 公钥对象
		RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
		// 以 Base64 对私钥进行编码
		String privateKeyString = Base64.encodeBase64String(privateKey.getEncoded());
		// 以 Base64 对公钥进行编码
		String publicKeyString = Base64.encodeBase64String(publicKey.getEncoded());
		keyMap.put(PUBLIC_KEY, publicKeyString);
		keyMap.put(PRIVATE_KEY, privateKeyString);
		return keyMap;
	}

	/**
	 * 获取RSA公钥
	 * 
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static RSAPublicKey getPublicKey(String publicKey) throws Exception {
		// 解码公钥字符串，得到公钥的 ASN.1 编码格式
		X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
		// 构建 RSA 的秘钥工厂
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 利用 RSA 秘钥工厂和 X509EncodedKeySpec 生成公钥
		return (RSAPublicKey) keyFactory.generatePublic(spec);
	}

	/**
	 * 获取RSA私钥
	 * 
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception {
		// 解码私钥字符串，得到私钥的 ASN.1 编码格式
		PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
		// 构建 RSA 的秘钥工厂
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 利用 RSA 秘钥工厂和 PKCS8EncodedKeySpec 生成私钥
		return (RSAPrivateKey) keyFactory.generatePrivate(spec);
	}
}
